package com.ax.center.service.impl;

import cn.hutool.core.util.StrUtil;
import com.ax.center.dto.ApiResponse;
import com.ax.center.entity.Announcement;
import com.ax.center.entity.AnnouncementReceiver;
import com.ax.center.enumeration.ExportFormat;
import com.ax.center.mapper.AnnouncementMapper;
import com.ax.center.service.AnnouncementReceiverService;
import com.ax.center.service.AnnouncementService;
import com.ax.center.service.UserRoleService;
import com.ax.center.urils.FileUploadUtil;
import com.ax.center.urils.TimeUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zy
 * @date 2023/7/7 15:54
 */
@Service
public class AnnouncementServiceImpl extends ServiceImpl<AnnouncementMapper, Announcement> implements AnnouncementService {

    @Autowired
    private AnnouncementMapper announcementMapper;
    @Autowired
    private  TaskScheduler taskScheduler;
    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private AnnouncementReceiverService announcementReceiverService;


//    @Transactional
//    @Override
//    public ApiResponse createAnnouncement(Announcement announcement,MultipartFile file) {
//        if(!file.isEmpty()){
//            return  createAnnouncementWithFile(announcement,file);
//        }
//        String publishTimeStr = announcement.getPublishTime();
//        if(StrUtil.isBlank(publishTimeStr)){
//            String nowTime = TimeUtils.getStartOfData(new Date());
//            announcement.setPublishTime(nowTime);
//        } else {
//            // 根据前端传递的时间格式，进行相应的日期时间字符串转换
//            LocalDateTime publishTime = LocalDateTime.parse(publishTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
//            if (publishTime.isAfter(LocalDateTime.now())) {
//                // 如果发布时间在当前时间之后，将任务添加到定时任务调度器中
//                scheduleAnnouncement(announcement);
//            }
//        }
//        save(announcement);
//        insertToReceviver(announcement);
//        return ApiResponse.ok("发布成功");
//    }
@Transactional(rollbackFor = Exception.class)
@Override
public ApiResponse createAnnouncement(Announcement announcement) {

    String publishTimeStr = announcement.getPublishTime();
    if(StrUtil.isBlank(publishTimeStr)||publishTimeStr.equals("")){
        String nowTime = TimeUtils.getStartOfData(new Date());
        announcement.setPublishTime(nowTime);
    } else {
        // 根据前端传递的时间格式，进行相应的日期时间字符串转换
        LocalDateTime publishTime = LocalDateTime.parse(publishTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        if (publishTime.isAfter(LocalDateTime.now())) {
            // 如果发布时间在当前时间之后，将任务添加到定时任务调度器中
         return  scheduleAnnouncement(announcement);
        }
    }
    save(announcement);
    insertToReceviver(announcement);
    return ApiResponse.ok(announcement.getId());
}

    private void insertToReceviver(Announcement announcement) {
        Long announcementId = announcement.getId();
        String targetAudience = announcement.getTargetAudience();
        List<Long> userIds = userRoleService.queryByRoleIds(targetAudience);

        List<AnnouncementReceiver> announcementUsers = userIds.stream()
                .map(userId -> {
                    AnnouncementReceiver announcementReceiver = new AnnouncementReceiver();
                    announcementReceiver.setAnnouncementId(announcementId);
                    announcementReceiver.setUserId(userId);
                    return announcementReceiver;
                })
                .collect(Collectors.toList());
        announcementReceiverService.saveAll(announcementUsers);

    }

    @Override
    public ApiResponse updateAnnouncement(Announcement announcement) {
        Long id = announcement.getId();
        update(announcement,null);
        return ApiResponse.ok("修改成功");
    }

    @Override
    public ApiResponse deleteAnnouncement(Long id) {
        if (query().eq("id",id).count()<=0) {
            return ApiResponse.fail("不存在该公告");
        }
        removeById(id);
        return ApiResponse.ok("删除成功");
    }

    @Override
    public ApiResponse getAnnouncementById(Long id) {
        Announcement one = query().eq("id", id).one();
        if(one==null){
            return ApiResponse.fail("公告不存在");
        }else {
            return ApiResponse.ok(one);
        }
    }


    @Transactional
    public ApiResponse createAnnouncementWithFile(Announcement announcement, MultipartFile file) throws IOException {

            String uploadFile = FileUploadUtil.uploadFile(file);
            announcement.setAttachments(uploadFile);
            // 判断时间是否为空
            String publishTimeStr = announcement.getPublishTime();
            if(StrUtil.isBlank(publishTimeStr)){
                String nowTime = TimeUtils.getStartOfData(new Date());
                announcement.setPublishTime(nowTime);
            } else {
                // 根据前端传递的时间格式，进行相应的日期时间字符串转换
                LocalDateTime publishTime = LocalDateTime.parse(publishTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                if (publishTime.isAfter(LocalDateTime.now())) {
                    // 如果发布时间在当前时间之后，将任务添加到定时任务调度器中
                 return   scheduleAnnouncement(announcement);
                }
            }
            save(announcement);
            insertToReceviver(announcement);
            return ApiResponse.ok("上传成功");

    }

    @Override
    public ApiResponse searchAnnouncements(String keyword, String publisher, LocalDateTime startTime, LocalDateTime endTime) {
        QueryWrapper<Announcement> queryWrapper = new QueryWrapper<>();

        if (StrUtil.isNotBlank(keyword)) {
            // 按关键字进行模糊匹配查询
            queryWrapper.like("title", keyword).or().like("content", keyword);
        }

        if (StrUtil.isNotBlank(publisher)) {
            // 按发布人进行精确匹配查询
            queryWrapper.eq("publisher", publisher);
        }

        if (startTime != null) {
            // 按发布时间大于等于起始时间进行查询
            queryWrapper.ge("publish_time", startTime.toString());
        }

        if (endTime != null) {
            // 按发布时间小于等于结束时间进行查询
            queryWrapper.le("publish_time", endTime.toString());
        }

        // 执行查询
        List<Announcement> announcements = announcementMapper.selectList(queryWrapper);

        return ApiResponse.ok(announcements);
    }


    @Override
    public ByteArrayResource exportAnnouncements(List<Announcement> announcements, ExportFormat format) throws IOException {
        String fileName = "announcements." + format.getExtension();
        String fileContent = generateFileContent(announcements, format);

        byte[] fileBytes;
        if (format == ExportFormat.DOC) {
            fileBytes = fileContent.getBytes(Charset.forName("GB2312"));
        } else {
            fileBytes = fileContent.getBytes(StandardCharsets.UTF_8);
        }

        ByteArrayResource resource = new ByteArrayResource(fileBytes);

        return  resource;
    }

    private String generateFileContent(List<Announcement> announcements, ExportFormat format) throws IOException {
        // 根据不同的导出格式，生成相应的文件内容
        switch (format) {
            case TXT:
                return generateTxtFileContent(announcements);
            case DOC:
                return generateDocFileContent(announcements);
            // 添加其他导出格式的生成方法
            default:
                throw new IllegalArgumentException("Unsupported export format: " + format);
        }
    }

    private String generateTxtFileContent(List<Announcement> announcements) {
        // 根据公告数据生成txt格式的文件内容
        StringBuilder sb = new StringBuilder();
        for (Announcement announcement : announcements) {
            sb.append("Title: ").append(announcement.getTitle()).append("\n");
            sb.append("Content: ").append(announcement.getContent()).append("\n");
            sb.append("-----\n");
        }
        return sb.toString();
    }

    private String generateDocFileContent(List<Announcement> announcements) throws IOException {
        // 创建一个新的文档对象
        XWPFDocument document = new XWPFDocument();
        // 添加标题和内容
        for (Announcement announcement : announcements) {
            // 创建段落对象
            XWPFParagraph paragraph = document.createParagraph();
            // 添加标题
            XWPFRun titleRun = paragraph.createRun();
            titleRun.setText("Title: " + announcement.getTitle());
            titleRun.setFontSize(14);
            titleRun.setBold(true);
            // 添加内容
            XWPFRun contentRun = paragraph.createRun();
            contentRun.setText("Content: " + announcement.getContent());
            contentRun.setFontSize(12);
            contentRun.setBold(false);
            // 添加段落之间的换行
            document.createParagraph();
        }
        // 将文档内容写入字节数组输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        document.write(outputStream);
        document.close();
        // 将字节数组输出流转换为字符串
        String string = outputStream.toString(Charset.forName("GB2312"));
        System.out.println(string);
        return string;
    }





    @Transactional
    @Async
    public ApiResponse scheduleAnnouncement(Announcement announcement) {
        String publishTimeStr = announcement.getPublishTime();
        LocalDateTime publishTime = LocalDateTime.parse(publishTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        taskScheduler.schedule(() -> {
           save(announcement);
           insertToReceviver(announcement);
        }, new CronTrigger(getCronExpression(publishTime)));
        return ApiResponse.ok("发布成功");
    }

    private String getCronExpression(LocalDateTime dateTime) {
        int second = dateTime.getSecond();
        int minute = dateTime.getMinute();
        int hour = dateTime.getHour();
        int dayOfMonth = dateTime.getDayOfMonth();
        int month = dateTime.getMonthValue();
        int year = dateTime.getYear();
        return String.format("%d %d %d %d %d *", second, minute, hour, dayOfMonth, month, year);
    }

}
